package wisecashier

import (
    "fmt"
    "sort"
	"errors"
	"strconv"
	"strings"
	"crypto"
	"encoding/pem"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"thirdpaysdk/utils/mapstruct"
	"github.com/astaxie/beego"
)

type WisecashierMsg struct {
	Status       string  `json:"status" form:"status"`
	OpenId       string  `json:"openid" form:"openid"`
	TradeType    string  `json:"trade_type" form:"trade_type"`
	ExchangeRate string  `json:"exchange_rate" form:"exchange_rate"`
	No           string  `json:"no" form:"no"`
	Currency     string  `json:"currency" form:"currency"`
	Amount       string  `json:"amount" form:"amount"`
	TradeTime    string  `json:"trade_time" form:"trade_time"`
	PayCurrency  string  `json:"pay_currency" form:"pay_currency"`
	PayAmount    string  `json:"pay_amount" form:"pay_amount"`
	AgentOrderId string  `json:"agent_order_id" form:"agent_order_id"`
}

func notifysign(fields map[string]string,publicKey,signature []byte,timestamp int64) error {
    basestring := ""
	var keys []string
	for k := range fields {
		keys = append(keys, k)
	}
	sort.Strings(keys)
	for _, k := range keys {
		basestring += k + "=" + fields[k] + "&"
	}
	midstring := strings.TrimSuffix(basestring, "&") + "," + strconv.FormatInt(timestamp, 10)
	err := rsaVerify(publicKey,midstring, signature)
	return err
}

//由于公钥只能进行验签，因此计算不出签名，只能采用此方法
func rsaVerify(pubKeyBytes []byte,origdata string,signData []byte) error {
	bSignData, err := base64.StdEncoding.DecodeString(string(signData))
	if err != nil {
		return fmt.Errorf("DecodeString sign error:%v", err)
	}
	digest := sHA256(origdata)
	block, _ := pem.Decode(pubKeyBytes)
	if block == nil {
		return errors.New("public key error")
	}
	publicInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
	if err != nil {
		return err
	}
	pub := publicInterface.(*rsa.PublicKey)
	err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, digest, bSignData)
	if err != nil {
		return fmt.Errorf("VerifyPKCS1v15 error:%v", err)
	}else{
	    beego.Debug("WisecashierMsg sign is ok......")
	}
	return nil
}

func WisecashierNotify(response *WisecashierMsg,publicKey,signature []byte,
					  timestamp int64) (map[string]string, error){
	var paramsMap map[string]string
	paramsMap = make(map[string]string)
	rspMap := mapstruct.Struct2Map(response, "json")
	for k, v := range rspMap {
		if s, ok := v.(string); ok {
			paramsMap[k] = s
		} else if _, ok := v.(int); ok {
			paramsMap[k] = strconv.Itoa(v.(int))
		} else {
			err := errors.New("格式错误，map 格式只支持string, int")
			return paramsMap, err
		}
	}
	err := notifysign(paramsMap,publicKey,signature,timestamp)
	return paramsMap, err
}
